<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3.promise的练习</title>
</head>
<body>
    
</body>
<script>
    // Promise()、.then .catch .finally 
    // static: resolve reject all race (allSettled any 不做要求)
    const PROMISE_STATUS_PENDING = 'pending'
    const PROMISE_STATUS_FULFILLED = 'fulfilled'
    const PROMISE_STATUS_REJECTED = 'rejected'

    class MyPromise {
        constructor(executor) {
            this.status = PROMISE_STATUS_PENDING
            this.value = undefined
            this.reason = undefined
            this.onfulfilledFns = []
            this.onrejectedFns = []

            const resolve = (value) => {
                if(this.status !== PROMISE_STATUS_PENDING) return
                this.status = PROMISE_STATUS_FULFILLED
                this.value = value
                this.onfulfilledFns.forEach(fn => fn())
            }

            const reject = (reason) => {
                if(this.status !== PROMISE_STATUS_PENDING) return
                this.status = PROMISE_STATUS_REJECTED
                this.reason = reason
                this.onrejectedFns.forEach(fn => fn())
            }

            executor(resolve, reject)
        }

        then(onFulfilled, onRejected) {
            return new MyPromise((resolve, reject)=>{
                if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled){
                    let result = onFulfilled(this.value)
                    resolve(result)
                }

                if(this.status === PROMISE_STATUS_REJECTED && onRejected){
                    let result = onRejected(this.reason)
                    reject(result)
                }
                
                if(this.status === PROMISE_STATUS_PENDING){
                    if(onFulfilled) {
                        this.onfulfilledFns.push(() => {
                            let result = onFulfilled(this.value)
                            resolve(result)
                        })
                    }
                    if(onRejected){
                        this.onrejectedFns.push(() => {
                            let result = onRejected(this.reason)
                            reject(result)
                        })
                    }
                }
            })
        }

        catch(onRejected) {
            return this.then(undefined, onRejected)
        }

        finally(onfinally) {
            this.then(
                () => {
                    onfinally()
                },
                () => {
                    onfinally()
                }
            )
        }

        static resolve(value) {
            return new MyPromise(resolve => resolve(value))
        }

        static reject(reason) {
            return new MyPromise((resolve, reject) => reject(reason))
        }

        static all(promises) {
            return new MyPromise((resolve, reject) => {
                const values = []
                promises.forEach(promise => {
                    promise.then(
                        res => {
                            values.push(res)
                            if(values.length === promises.length){
                                resolve(res)
                            }                            
                        },
                        err => {
                            reject(err)
                        }
                    )
                })
            })
  
        }

        static race(promises) {
            return new MyPromise((resolve, reject) => {
                promises.forEach(promise => {
                    promise.then(
                        res => {
                            resolve(res)
                        },
                        err => {
                            reject(err)
                        }
                    )
                })
            })

        }
    }

    let p1 = new MyPromise((resolve) => {
        resolve('优质')
    }).then(res => {
        console.log('res1:', res)
        return res + 1
    }).then(res => {
        console.log('res2:', res)
        return res + 2
    }).then(res => {
        console.log('res3:', res)
        return res + 3
    })

    console.log('p1:', p1)
</script>
</html>